package com.jt.base.utils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * RSA--解码
 */
public class PassWordDecrypt {


    public static String decrypt(String encrypStr,String privateKey) throws Exception {
        return privateDecrypt(encrypStr,getPrivateKey(privateKey));
    }

    /**
     * 得到私钥
     *
     * @param privateKey 密钥字符串（经过base64编码过后的）
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static RSAPrivateKey getPrivateKey(String privateKey) throws Exception {
        //通过PKCS#8编码的Key指令获得私钥对象
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        return key;
    }

    /**
     * 得到公钥
     *
     * @param publicKey 密钥字符串（经过base64编码）
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        //通过X509编码的Key指令获得公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
        return key;
    }

    /**
     * 私钥解密
     *
     * @param data       加密后的字符串
     * @param privateKey 私钥
     * @return 原文
     */
    public static String privateDecrypt(String data, RSAPrivateKey privateKey) {
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data), privateKey.getModulus().bitLength()), "UTF-8");
        } catch (Exception e) {
            throw new RuntimeException("私钥解密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 分段加密（当加密长度大于密钥长度）
     *
     * @param cipher
     * @param opmode
     * @param datas
     * @param keySize
     * @return
     */
    public static byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {
        int maxBlock = 0;
        if (opmode == Cipher.DECRYPT_MODE) {
            maxBlock = keySize / 8;
        } else {
            maxBlock = keySize / 8 - 11;
        }
        int offSet = 0;
        byte[] buff;
        int i = 0;
        try( ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            while (datas.length > offSet) {
                if (datas.length - offSet > maxBlock) {
                    buff = cipher.doFinal(datas, offSet, maxBlock);
                } else {
                    buff = cipher.doFinal(datas, offSet, datas.length - offSet);
                }
                out.write(buff, 0, buff.length);
                i++;
                offSet = i * maxBlock;
            }
            byte[] resultDatas = out.toByteArray();
            return resultDatas;
        } catch (Exception e) {
            throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e);
        }
    }

    /**
     * 生成密钥对
     *
     * @return
     */
    public static Map<String, String> pulicsKey() {
        KeyPairGenerator keyPairGenerator;
        Map<String, String> map = new HashMap<>();
        try {
            //为RSA算法创建一个KeyPairGenerator对象
            keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            //初始化KeyPairGenerator对象的密钥长度（一般为1024比较好）
            keyPairGenerator.initialize(1024);

            //生成密钥对
            KeyPair pair = keyPairGenerator.generateKeyPair();
            //获取公钥
            Key publicKey = pair.getPublic();
            //使用org.apache.commons.codec.binary.Base64包中Base64进行编码
            String publicKeyStr = Base64.encodeBase64URLSafeString(publicKey.getEncoded());
            String  publicKeyResult = new String(Base64.encodeBase64(getPublicKey(publicKeyStr).getEncoded()));

            //获取密钥
            Key privateKey = pair.getPrivate();
            String privateKeyStr = Base64.encodeBase64URLSafeString(privateKey.getEncoded());
           String  privateResult = new String(Base64.encodeBase64(getPrivateKey(privateKeyStr).getEncoded()));
            map.put("publicKey", publicKeyResult);
            map.put("privateKey", privateResult);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }



    public static void main(String[] args) throws Exception {
        System.out.println(pulicsKey());
    }
}
